package com.tjetc._1collection._1list;

import java.util.ArrayList;
import java.util.Vector;

@SuppressWarnings("all")
public class _2ArrayListDetail {
    public static void main(String[] args) {
        /*
            ArrayList的概述：
                1.可以存null 并有多个
                2. transient Object[] elementData; 这是底层维护了一个数组
                3. Vector 是最初的集合类 他是线程安全的 ArrayList是线程不安全的
            ArrayList底层结论：
                1. 当创建ArrayList对象时，如果使⽤的是⽆参构造器，则初始elementData容量为0, 第1次添
                加，则扩容elementData为10,如需要再次扩容，则扩容elementData为1.5倍。
                2. 如果使⽤的是指定⼤⼩的构造器，则初始elementData容量为指定⼤⼩，如果需要扩容， 则
                直接扩容当前容量elementData为1.5倍。
         */

        /*
            -----------------------当ArrayList对象中维护的数组为{} 时的首次add 分析-----------------------
            1.将ArrayList父类对象创建
            2.构造ArrayList对象
            public ArrayList() {
                将底层数组赋值为默认容量的空的元素数据 {}
                this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
            }

            3.执行首次add操作 集合只能保存对象 不能保存基本数据类型
            public boolean add(E e) {
                fast-fail机制
                modCount++;
                执行真正的添加
                add(e, elementData, size);
                return true;
            }
            4. 执行真正的add方法
            e： 传进的元素
            elementData： 数组
            s： 当前的数组个数 默认开始为0
            private void add(E e, Object[] elementData, int s) {
                判断当前的数组长度和当前数组的个数是否相等
                if (s == elementData.length)
                    执行扩容
                    elementData = grow();
                elementData[s] = e;
                size = s + 1;
            }
            5. 执行扩容
            private Object[] grow() {
                返回扩容后的新数组
                return grow(size + 1);
            }

            6. 执行真正的扩容
            minCapacity： 当前数组的个数 + 1
            private Object[] grow(int minCapacity) {
            获取旧的容量 = 当前的数组长度
            int oldCapacity = elementData.length; 0
                判断当前的老的容量是否大于0
                当前的数组并不是一个空数组
                if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
                    int newCapacity = ArraysSupport.newLength(oldCapacity,
                    minCapacity - oldCapacity,
                    oldCapacity >> 1 );
                    return elementData = Arrays.copyOf(elementData, newCapacity);
                } else {
                    重新new了一个新数组，新数组的长度最小的容量和默认容量的最大
                    return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)];
                }
            }
            执行完后，此时新new的数组的长度为10

            7. 执行往新数组添加元素 在0号索引添加新元素
            elementData[s] = e;

            8. 对象中的size + 1 也就是现有的元素个数为1
            size = s + 1;

            ------------------------------ 在已有数组的基础执行 add操作时第二次扩容 分析---------------
            1.执行完首次添加后 数组的长度此时为10 个数size为1
            2.执行添加 发现此时默认的10个已经装满了
            private void add(E e, Object[] elementData, int s) {
                此时这个条件为true 需要进行扩容
                if (s == elementData.length)
                    elementData = grow();
                elementData[s] = e;
                size = s + 1;
            }
            3.执行扩容
            private Object[] grow(int minCapacity) {
            获取旧的容量 = 当前的数组长度
            int oldCapacity = elementData.length; 10
                当前 符合oldCapacity > 0 条件
                if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
                    参数：
                        oldCapacity： 老的容量
                        minCapacity - oldCapacity：
                        oldCapacity >> 1 要扩容多少 算术右移 二进制 向右移动 / 2 0.5
                    int newCapacity = ArraysSupport.newLength(oldCapacity,
                    minCapacity - oldCapacity,
                    oldCapacity >> 1 );
                    return elementData = Arrays.copyOf(elementData, newCapacity);
                } else {
                    return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)];
                }
            }
            4.执行扩容的真正方法
            oldLength： 老的长度  10
            minGrowth： 最小增长的个数 1
            prefGrowth：要扩容的数量
            public static int newLength(int oldLength, int minGrowth, int prefGrowth) {
            计算能不能装的下 10 + 1
            prefLength = 11
            SOFT_MAX_ARRAY_LENGTH: 能容下的最大长度
                处理特殊情况：如果初始容量只有1个的时候 会出现扩容0的情况 防止出现这种情况 使用Math.max() 进行处理
            oldLength + Math.max(minGrowth, prefGrowth); 扩容1.5倍的地方
            int prefLength = oldLength + Math.max(minGrowth, prefGrowth); // might overflow
            if (0 < prefLength && prefLength <= SOFT_MAX_ARRAY_LENGTH) {
                return prefLength;
            } else {
                一般不会走到这个
                // put code cold in a separate method
                return hugeLength(oldLength, minGrowth);
            }

            5. 执行数组的拷贝 将原有数组中的数据按照新的容量进行拷贝
                然后将原有数组的引用指向新的数组的位置
            return elementData = Arrays.copyOf(elementData, newCapacity);
        }

         */
        ArrayList arrayList = new ArrayList();
        Vector vector = new Vector();

        for (int i = 0; i < 10; i++) {
            arrayList.add(1);
        }

        // 演示首次满足10个长度后的扩容
        arrayList.add(1);

        /*
            ----------------------演示在创建对象时给出默认的容量后的扩容机制----------------
            1.开始创建对象 走的是有参构造
            public ArrayList(int initialCapacity) {
                如果给的容量 > 0
                if (initialCapacity > 0) {
                    直接根据你给的容量创建了一个新数组并指向老数组
                    this.elementData = new Object[initialCapacity];
                } else if (initialCapacity == 0) {
                    如果给的容量 = 0 那么初始的数组也是个空数组 走的逻辑和之前无参构造是一样的
                    this.elementData = EMPTY_ELEMENTDATA;
                } else {
                    throw new IllegalArgumentException("Illegal Capacity: "+
                                                       initialCapacity);
                }
            }

         */





        // 演示具有初始容量
        ArrayList arrayList1 = new ArrayList(5);
        for (int i = 0; i < 5; i++) {
            arrayList1.add(1);
        }
        // 演示首次满足10个长度后的扩容
        arrayList1.add(1);
    }
}
